# automation.py
import re
import os
import asyncio
import random
import base64
import shutil
import string
from urllib.parse import urlencode

import aiohttp
import aiofiles
from loguru import logger
from datetime import datetime
from typing import Tuple
from bit_api_gui import BitAPI
from tools import EmailAPI, YesCaptchaSolver, get_extension_path
from ee import connect_pop3_async, connect_host_async
from playwright.async_api import async_playwright, TimeoutError as PlaywrightTimeoutError, expect

# 全局文件锁用于线程安全地写入文件
file_lock = asyncio.Lock()
bit_api_lock = asyncio.Lock()
TIME_OUT_S = 1000 * 10 * 3

# 名字和姓氏列表
FIRST_NAMES = ['John', 'Emma', 'Michael', 'Sophia', 'James', 'Olivia', 'William', 'Ava',
               'Alexander', 'Emily', 'Daniel', 'Charlotte', 'Benjamin', 'Mia', 'Jacob', 'Harper',
               'Ethan', 'Abigail', 'Henry', 'Ella', 'Sebastian', 'Scarlett', 'Jack', 'Amelia',
               'Liam', 'Isabella', 'Noah', 'Sophia', 'Logan', 'Avery', 'Lucas', 'Grace',
               'Mason', 'Aria', 'Elijah', 'Evelyn', 'Oliver', 'Chloe', 'Jacob', 'Zoe',
               'Ethan', 'Lily', 'Aiden', 'Madison', 'Caden', 'Riley', 'Jackson', 'Nora']

LAST_NAMES = ['Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis',
              'Rodriguez', 'Martinez', 'Hernandez', 'Lopez', 'Gonzalez', 'Wilson', 'Anderson',
              'Thomas', 'Taylor', 'Moore', 'Jackson', 'White', 'Harris', 'Martin', 'Thompson',
              'Lee', 'Walker', 'Perez', 'Hall', 'Young', 'Allen', 'Sanchez', 'Wright', 'King',
              'Scott', 'Green', 'Baker', 'Adams', 'Nelson', 'Hill', 'Ramirez', 'Campbell',
              'Mitchell', 'Roberts', 'Carter', 'Phillips', 'Evans', 'Turner', 'Torres', 'Parker']

tweets = [
    "Hello world!",
    "Just setting up my account.",
    "Excited to be here!",
    "What's up everyone?",
    "Happy to join the community!",
    "Hello Twitter! Excited to explore this world. 🎉",
    "Just joined Twitter! What’s happening here? 🐦",
    "Finally took the plunge—here I am! 🙌",
    "New here. Let’s see what all the buzz is about! 🚀",
    "Hello, world! It’s great to be here. 🌍",
    "Just joined Twitter! I’m passionate about [your hobby/interest]. Let’s connect!",
    "Big fan of tech, music, and travel. What’s trending in these spaces?",
    "Excited to share and learn about photography, art, and creativity! 📸🎨",
    "Avid gamer and foodie. Can’t wait to see what’s happening here! 🎮🍕",
    "Here for the memes and meaningful discussions. Let’s go! 😂🗣️",
    "First tweet—did I do this right? 🤔",
    "Just joined Twitter. What’s the first rule of tweeting?",
    "Am I a Twitter bird now? 🐦",
    "OK, Twitter. Be gentle with me.",
    "Is this where the cool kids hang out?",
    "Here to discuss the latest trends in [field]. Let’s dive in!",
    "Just joined—what’s the best way to navigate Twitter?",
    "New here! Any pro tips for a Twitter newbie?",
    "Hey Twitter, what should I tweet first?",
    "Best accounts to follow for someone new here? Recommendations?",
    "What's the most important unwritten rule of Twitter?",
    "Finally joined the Twitterverse. It’s about time!",
    "This is my first step into a larger world. Let’s make it count!",
    "Feeling like a small fish in a big pond. Excited to explore!",
    "New beginnings, new platform, and new connections. Let’s go!",
    "Here’s to making meaningful connections and sharing great ideas. Cheers!",
]


def generate_password(length=18):
    # 定义字符集合：数字、大写字母、小写字母
    characters = string.ascii_letters + string.digits
    # 随机生成密码
    password = ''.join(random.choice(characters) for _ in range(length))
    return password


def calculate_date_of_birth(age: int) -> Tuple[int, int, int]:
    """根据年龄随机生成出生日期"""
    today = datetime.today()
    birth_year = today.year - age
    month = random.randint(1, 12)
    day = random.randint(1, 28)  # 简化处理，避免不同月份的天数问题
    return birth_year, month, day


def generate_random_full_name() -> Tuple[str, str]:
    """生成随机的名字和姓氏"""
    first_name = random.choice(FIRST_NAMES)
    last_name = random.choice(LAST_NAMES)
    return first_name, last_name


async def download_image_async(img_url):
    """下载图片并返回Base64编码"""
    try:
        async with aiohttp.ClientSession() as session:
            async with session.get(img_url) as response:
                if response.status == 200:
                    content = await response.read()
                    content_type = response.headers.get('Content-Type', 'image/jpeg')
                    img_base64 = base64.b64encode(content).decode('utf-8')
                    return f"data:{content_type};base64,{img_base64}"
                else:
                    return await download_image_async(img_url)
    except aiohttp.ClientError as e:
        logger.error(f"图片下载失败: {e}")
        return None


async def process_captcha_images(page, url_pattern, YES_API_KEY):
    retries = 0
    max_retries = 10
    verify_button, sel_frame = await find_element_in_page_and_iframes(page, 'button', 'Authenticate',
                                                                      timeout=TIME_OUT_S)
    while not verify_button and retries < max_retries:
        verify_button, sel_frame = await find_element_in_page_and_iframes(page, 'button', 'Authenticate',
                                                                          timeout=TIME_OUT_S)
        retries += 1
        await page.wait_for_timeout(2000)
        if retries >= max_retries:
            logger.error("达到最大重试次数，无法找到“Authenticate”按钮。")
            return

    if not verify_button:
        return

    await page.wait_for_timeout(100)
    await verify_button.click()

    # 捕获验证码图片请求
    while True:
        try:
            async with page.expect_request(lambda request: url_pattern.match(request.url),
                                           timeout=TIME_OUT_S) as request_info:
                request = await request_info.value
                img_url = request.url
        except PlaywrightTimeoutError:
            logger.warning("等待验证码图片请求超时")
            break

        if not img_url:
            logger.warning("未捕获到验证码图片 URL")
            break

        logger.info(f"捕获到的验证码图片 URL: {img_url}")

        # 获取当前验证码标题
        title = await sel_frame.locator('[role="text"]').text_content()
        logger.info(f"当前验证码标题: {title}")

        # 提取当前步骤和总步骤数
        match = re.search(r'\((\d+) of (\d+)\)', title)
        if not match:
            logger.error("标题格式不正确，退出处理...")
            break

        current_step = int(match.group(1))
        total_steps = int(match.group(2))
        logger.info(f"正在处理第 {current_step} 张，共 {total_steps} 张验证码")

        # 下载图片并获取 Base64 编码
        img_base64 = await download_image_async(img_url)
        if img_base64:
            solver = YesCaptchaSolver(YES_API_KEY)
            await handle_recaptcha_async(sel_frame, title, img_base64, solver)

            submit_button = sel_frame.locator('button:text("Submit")')
            await submit_button.click()

        # 如果处理完成，退出循环
        if current_step == total_steps:
            logger.info("所有验证码已处理完成！")
            break
        else:
            logger.info(f"已处理 {current_step} / {total_steps}，继续处理下一张验证码...")


async def find_element_in_page_and_iframes(page, selector, text, timeout=40000):
    element = page.locator(f'{selector}:has-text("{text}")')
    if await element.count() > 0:
        await element.wait_for(state="visible", timeout=timeout)
        return element, None

    # 遍历所有顶级 frame 查找目标元素
    for frame in page.frames:
        # 先在当前 frame 查找目标元素
        element, sel_frame = await find_first_element_in_iframes(frame, selector, text, timeout)
        if element:
            return element, sel_frame  # 找到后返回

    return None, None  # 如果未找到目标元素


async def find_first_element_in_iframes(frame, selector, text, timeout=40000):
    try:
        # 在当前 frame 中查找目标元素
        element = frame.locator(f'{selector}:has-text("{text}")')
        if await element.count() > 0:
            await element.wait_for(state="visible", timeout=timeout)
            return element, frame
    except Exception as e:
        pass
    # 递归查找子 iframe
    for child_frame in frame.child_frames:  # 获取当前 frame 的所有子 iframe
        element, sel_frame = await find_first_element_in_iframes(child_frame, selector, text, timeout)
        if element:
            return element, sel_frame

    return None, None


async def handle_recaptcha_async(frame, title, img_base64, solver):
    """处理验证码提交逻辑"""
    try:
        task_id = await solver.create_img_task(title, img_base64)
        logger.info(f"任务已创建，task_id: {task_id}")

        g_recaptcha_response = await solver.get_task_result(task_id)
        if not g_recaptcha_response:
            logger.warning("未能获取验证码结果")
            return

        logger.info(f"获取到的 gRecaptchaResponse: {g_recaptcha_response[0]}")

        right_arrow = frame.locator('[aria-label="Navigate to next image"]')
        for _ in range(g_recaptcha_response[0]):
            await right_arrow.click()
            await frame.page.wait_for_timeout(200)  # 可以根据实际情况调整等待时间
    except Exception as e:
        logger.error(f"处理验证码时发生错误: {e}")


async def click_button(page, locator, timeout=10000):
    try:
        button = page.locator(locator)
        await button.wait_for(state="visible", timeout=timeout)
        await button.click()
        logger.info(f"点击按钮成功: {locator}")
        return True
    except PlaywrightTimeoutError:
        logger.warning(f"按钮 {locator} 在指定时间内不可见。")
        return False


async def upload_file(page, file_input_selector, FILE_PATHS):
    try:
        background_image = random.choice(FILE_PATHS)
        await page.wait_for_selector(file_input_selector, timeout=10000)
        file_input = page.locator(file_input_selector)
        await file_input.set_input_files(background_image)
        logger.info(f"已上传文件：{background_image}")
    except PlaywrightTimeoutError:
        logger.error(f"文件输入框 {file_input_selector} 未找到。")


async def handle_skip_buttons(page, skip_count=2):
    for _ in range(skip_count):
        if await click_button(page, 'text=Skip for now'):
            await asyncio.sleep(0.5)  # 可以调整或移除
        else:
            break


async def click_random_follow_buttons(page, max_clicks=3):
    try:
        await page.wait_for_selector('button[aria-label^="Follow"]', timeout=10000)
        buttons = page.locator('button[aria-label^="Follow"]')
        count = await buttons.count()

        if count < max_clicks:
            selected_indices = list(range(count))
        else:
            selected_indices = random.sample(range(count), max_clicks)

        for index in selected_indices:
            button = buttons.nth(index)
            if await button.is_visible():
                await button.click()
                await asyncio.sleep(0.2)  # 可以调整或移除
        await click_button(page, 'button:has-text("Next")')
    except PlaywrightTimeoutError:
        logger.warning("未找到“Follow”按钮。")


async def click_button_with_retry(page, selector, max_retries=3, retry_interval=2500):
    """
    尝试点击按钮，最多重试指定次数。
    """
    for attempt in range(max_retries):
        tweet_button = page.locator(selector)

        # 使用 evaluate 检查并点击按钮
        is_clicked = await page.evaluate('''
            (button) => {
                if (!button || button.disabled) {
                    return false; // 按钮不存在或禁用
                }
                button.click();
                return true; // 成功点击
            }
        ''', tweet_button)

        if is_clicked:
            print(f"按钮已点击（尝试次数: {attempt + 1}）")
            return True
        else:
            print(f"按钮不可用，等待 {retry_interval} 毫秒后重试...（尝试次数: {attempt + 1}）")
            await page.wait_for_timeout(retry_interval)

    print("按钮点击失败，达到最大重试次数")
    return False


async def post_tweet(page, num_messages, message_list, activity_enabled, activity_img_enabled, user_activity_img_list,
                     log_callback):
    msg = random.choices(message_list)
    for i in range(num_messages):
        try:
            # 检查是否发送文本
            if activity_enabled:
                await page.wait_for_selector('[aria-label="Post text"]', timeout=TIME_OUT_S)
                text_input = page.locator('[aria-label="Post text"]')
                await text_input.click()
                await text_input.type(msg[0])

            # 检查是否发送图片
            if activity_img_enabled and len(user_activity_img_list) > 0:
                img = random.choices(user_activity_img_list)
                file_input = page.locator('input[data-testid="fileInput"]').first
                await file_input.set_input_files(img)
                await page.wait_for_timeout(500)
            try:
                # 等待 "tweetButtonInline" 按钮出现并可见，最多等待10秒
                tweet_button = page.locator('button[data-testid="tweetButtonInline"]')
                # await tweet_button.wait_for(state="visible", timeout=TIME_OUT_S)  # 10秒超时
                await expect(tweet_button).to_be_enabled(timeout=TIME_OUT_S)

                # 点击 "tweetButtonInline" 按钮
                await tweet_button.evaluate("button => button.click()")
                logger.info(f'发布推文成功')
                log_callback(f"发布推文成功")

            except Exception as e:
                logger.info(f"发布推文错误。{e}")
                log_callback(f"发布推文错误。请10秒种内手动点击发布，10秒后跳过")
                await page.wait_for_timeout(10000)

            await page.wait_for_selector('button:has-text("Got it")', timeout=TIME_OUT_S)
            if await page.locator('button:has-text("Got it")').is_visible():
                await page.locator('button:has-text("Got it")').click()
                logger.info("已点击“Got it”按钮。")
                await page.wait_for_timeout(500)
        except Exception as e:
            logger.error("发布推文时发生错误。")


async def set_profile(page, upload_background_enabled, user_profile_list, user_address_list, upload_images):
    try:
        bio = "这是我的个人简介。"
        location = "Hong Kong, china"

        if user_profile_list:
            bio = random.choices(user_profile_list)[0]
        if user_address_list:
            location = random.choices(user_address_list)[0]

        await click_button(page, 'a[data-testid="editProfileButton"]')

        # 填写Bio
        try:
            bio_textarea = page.locator('textarea[name="description"]')
            await bio_textarea.wait_for(state="visible", timeout=TIME_OUT_S)
            await bio_textarea.fill(bio)
            logger.info("已填写 Bio。")
        except PlaywrightTimeoutError:
            logger.error("Bio 输入框未找到。")

        # 填写Location
        try:
            location_input = page.locator('input[name="location"]')
            await location_input.wait_for(state="visible", timeout=TIME_OUT_S)
            await location_input.fill(location)
            logger.info("已填写 Location。")
        except PlaywrightTimeoutError:
            logger.error("Location 输入框未找到。")

        if upload_background_enabled and upload_images:
            # 上传背景图
            try:
                background_image = random.choice(upload_images)
                file_input = page.locator('input[data-testid="fileInput"]').first
                await file_input.set_input_files(background_image)
                logger.info(f"已上传背景图：{background_image}")
                # await page.wait_for_timeout(1000)
                await click_button(page, 'button[data-testid="applyButton"]')
                await page.wait_for_timeout(1000)

            except PlaywrightTimeoutError:
                logger.error("背景图上传失败。")
        else:
            logger.info("未提供图片路径，跳过背景图上传。")
            await handle_skip_buttons(page)

            try:
                bio_textarea = page.locator('textarea[data-testid="ocfEnterTextTextInput"]')
                await bio_textarea.wait_for(state="visible", timeout=TIME_OUT_S)
                await bio_textarea.fill(bio)
                logger.info("已填写 Bio。")

                await click_button(page, '[data-testid="ocfEnterTextNextButton"]')

                await page.wait_for_timeout(1000)
            except PlaywrightTimeoutError:
                logger.error("Bio 输入框未找到。")
            try:
                location_textarea = page.locator('input[data-testid="ocfEnterTextTextInput"]')
                await location_textarea.wait_for(state="visible", timeout=TIME_OUT_S)
                await location_textarea.fill(location)
                logger.info("已填写 location。")
                await click_button(page, 'text=Next')
            except PlaywrightTimeoutError:
                logger.error("location 输入框未找到。")

        # 保存更改
        await page.wait_for_timeout(1000)
        if await click_button(page, 'button[data-testid="Profile_Save_Button"]'):
            await page.wait_for_timeout(2000)
            logger.info("已保存个人资料。")
    except Exception as e:
        logger.error(f"设置个人资料时发生错误：{e}")


async def call_to_action(page):
    action_button = page.locator('button[data-testid="OCF_CallToAction_Button"]')
    if await action_button.is_visible():
        await click_button(page, 'button[data-testid="OCF_CallToAction_Button"]')
        logger.info("同意协议。")


async def update_images(page, avatar_images):
    FILE_PATHS = random.choices(avatar_images)
    if not FILE_PATHS:
        logger.info("没有提供图片路径，跳过图片上传。")
        return
    await upload_file(page, 'input[type="file"]', FILE_PATHS)
    await click_button(page, 'button[data-testid="applyButton"]')
    await asyncio.sleep(0.5)
    await click_button(page, 'text=Next')
    logger.info("图片上传完成。")


async def extract_token(cookies, name):
    for cookie in cookies:
        if cookie['name'] == name:
            return cookie['value']
    return None


async def select_username(page):
    username_locator = page.locator('input[name="username"]')
    username_value = await username_locator.input_value()
    await handle_skip_buttons(page)
    return username_value


async def choose_language(page):
    try:
        await page.wait_for_selector('span:has-text("Which languages do you speak?")', timeout=2000)
        languages_message = page.locator('span:has-text("Which languages do you speak?")')
        if await languages_message.is_visible():
            await click_button(page, 'text=Next')
            logger.info("选择语言完成。")
    except PlaywrightTimeoutError:
        logger.info("未出现选择语言。")


async def follow_accounts(page):
    try:
        await page.wait_for_selector('button:has-text("Follow")', timeout=TIME_OUT_S)
        follow_buttons = page.locator('button:has-text("Follow")')
        button = follow_buttons.first
        if await button.is_visible():
            await button.click()
            logger.info("已点击第一个“Follow”按钮。")
    except PlaywrightTimeoutError:
        logger.warning("在指定时间内未找到“Follow”按钮。")

    next_button = page.get_by_text("Next")
    if await next_button.count() > 1:
        next_button = next_button.last
    try:
        await next_button.wait_for(state="visible", timeout=TIME_OUT_S)
        await next_button.click()
        logger.info("已点击“Next”按钮。")
    except PlaywrightTimeoutError:
        logger.error("“Next”按钮不可见。")

    try:
        # await page.wait_for_selector('button:has-text("OK")', timeout=2000)
        ok_buttons = page.locator('button:has-text("OK")')
        if await ok_buttons.count() > 0:
            await ok_buttons.first.click()
            logger.info("已点击“OK”按钮。")
    except PlaywrightTimeoutError:
        logger.warning("未找到“OK”按钮。")


async def follow_random_topics(page):
    await click_random_follow_buttons(page, max_clicks=3)
    logger.info("已关注随机主题。")


async def handle_signup(page, email, t1, client_id, email_pop_host, email_pop_prot, password, firstname, lastname,
                        birth_year, month, day, SIGNUP_URL,
                        YES_API_KEY, use_api_captcha, TARGET_SENDER, CAPTCHA_URL_PATTERN, log_callback):
    signup_success = False  # 初始化成功标志

    try:
        await page.goto(SIGNUP_URL, timeout=TIME_OUT_S)

        await page.wait_for_selector('span:has-text("Create account")', timeout=TIME_OUT_S)
        await page.get_by_role("button", name="Create account").click()
        await page.get_by_label("Name").fill(f"{firstname} {lastname}")
        logger.info(f"填写名称: {firstname} {lastname}")
        log_callback(f"填写名称: {firstname} {lastname}")
        # 使用邮箱注册
        try:
            use_email_button = page.get_by_role("button", name="Use email instead")
            if await use_email_button.is_visible():
                await use_email_button.click()
                logger.info("点击“Use email instead”按钮。")
        except PlaywrightTimeoutError:
            logger.warning("未找到“Use email instead”按钮。")

        await page.get_by_label("Email").fill(email)

        await page.locator('select#SELECTOR_1').select_option(value=str(month))
        await page.locator('select#SELECTOR_2').select_option(value=str(day))
        await page.locator('select#SELECTOR_3').select_option(value=str(birth_year))
        logger.info(f"填写生日: {birth_year}-{month}-{day}")

        await page.wait_for_load_state("networkidle")
        await page.wait_for_timeout(2000)
        next_btn = page.locator('[data-testid="ocfSignupNextLink"]')
        await next_btn.click()

        # 处理验证码
        await page.wait_for_load_state("networkidle")
        await page.wait_for_timeout(2000)
        if use_api_captcha:
            if await page.locator('[data-testid="ocfSettingsListNextButton"]').is_visible():
                await page.locator('[data-testid="ocfSettingsListNextButton"]').click()

            await page.wait_for_timeout(2000)
            verification_element = await page.query_selector('input[name="verfication_code"]')
            if not verification_element:
                try:
                    await process_captcha_images(page, CAPTCHA_URL_PATTERN, YES_API_KEY)
                except Exception as e:
                    logger.error(f"获取或填写验证码时发生错误：{e}")
                    log_callback(f"打码/获取验证码失败")
                    return False
            else:
                logger.info("无须打码。")
                log_callback("无须打码")
        else:
            await page.wait_for_selector('input[name="verfication_code"]', timeout=60000)
        # 获取邮件验证码
        try:
            await page.wait_for_selector('input[name="verfication_code"]', timeout=10000)
            # 在这里调用您的邮件接收函数，获取验证码
            log_callback("获取验证码中")
            if t1 == '自建邮箱':
                code = await connect_host_async(email, password, email_pop_host, email_pop_prot, TARGET_SENDER)
            elif t1 == 'Firstmail':
                code = await connect_host_async(email, password, 'imap.firstmail.ltd', 110, TARGET_SENDER)
            else:
                code = await connect_pop3_async(email, client_id, t1, TARGET_SENDER)
            if not code:
                logger.error("未能获取验证码。")
                log_callback(f"未能获取验证码")
                return False  # 验证码获取失败
            await page.get_by_label("Verification code").fill(code)
            await page.get_by_role("button", name="Next").click()
            logger.info("填写验证码并点击“Next”。")
        except Exception as e:
            logger.error(f"获取或填写验证码时发生错误：{e}")
            log_callback(f"打码/获取验证码失败")
            return False
        await page.wait_for_timeout(1000)
        try:
            verification_error_message = page.locator('span:has-text("complete your signup right now.")')
            if await verification_error_message.is_visible():
                logger.error("注册错误提示出现。")
                return False
        except Exception:
            pass
        # 设置密码
        try:
            log_callback("设置密码")
            await page.wait_for_selector('input[name="password"]', timeout=TIME_OUT_S)
            password_input = page.locator('input[name="password"]')
            await password_input.type(password, delay=50)
            await page.get_by_role("button", name="Sign up").click()
            logger.info("填写密码并点击“Sign up”。")
        except PlaywrightTimeoutError:
            logger.error("密码输入框未找到。")
            return False

        # 检查错误信息
        try:
            await page.wait_for_selector('input[type="file"]', timeout=10000)
            error_message = page.locator('span:has-text("Oops, something went wrong. Please try again later.")')
            if await error_message.is_visible():
                logger.error("注册过程中出现错误。")
                return False
            else:
                signup_success = True  # 未检测到错误信息，认为注册成功
        except PlaywrightTimeoutError:
            logger.info("未发现注册错误。")
            signup_success = True  # 未检测到错误信息，认为注册成功

    except Exception as e:
        logger.error(f"注册过程中发生错误：{e}")
        signup_success = False

    return signup_success


async def search_and_browse_users(page, config):
    try:
        browse_users_name = config['search_user_config']['browse_users_name']
        browse_users_count = config['search_user_config']['browse_users_count']
        browse_times = config['search_user_config']['browse_times']
        browse_duration = config['search_user_config']['browse_duration']

        # 构造搜索URL并访问
        params = {
            'q': browse_users_name,
            'src': 'typed_query',
            'f': 'user'
        }

        search_url = f"https://x.com/search?{urlencode(params)}"
        # 遍历每个用户
        for user_index in range(browse_users_count):
            try:
                # 每次都重新访问搜索页面
                await page.goto(search_url)

                # 等待并获取用户列表
                await page.wait_for_selector('[data-testid="UserCell"]')
                user_cells = await page.query_selector_all('[data-testid="UserCell"]')

                if user_index >= len(user_cells):
                    logger.info(f"No more users to browse after index {user_index}")
                    break

                # 获取用户名称用于日志
                current_user = user_cells[user_index]
                user_name = await current_user.evaluate('el => el.textContent')
                logger.info(f"Browsing user {user_index + 1}/{browse_users_count}: {user_name}")

                # 对同一个用户重复访问指定次数
                for visit in range(browse_times):
                    logger.info(f"Visit {visit + 1}/{browse_times} for current user")

                    # 重新获取用户列表和当前用户元素
                    await page.wait_for_selector('[data-testid="UserCell"]')
                    user_cells = await page.query_selector_all('[data-testid="UserCell"]')
                    current_user = user_cells[user_index]

                    # 点击进入用户页面
                    await current_user.click()
                    await page.wait_for_load_state('domcontentloaded')

                    # 随机滚动页面
                    await page.evaluate('window.scrollBy(0, Math.random() * 500)')

                    # 停留指定时间
                    await asyncio.sleep(browse_duration)

                    # 返回搜索页面
                    await page.go_back()
                    await page.wait_for_load_state('domcontentloaded')

                    # 确保完全加载
                    await page.wait_for_timeout(1000)

            except Exception as e:
                logger.error(f"Error browsing user {user_index}: {e}")
                # 如果出错，确保返回搜索页面
                try:
                    await page.goto(search_url)
                except:
                    pass
                continue

    except Exception as e:
        logger.error(f"Error in search_and_browse_users: {e}")


async def process_account(line_str, config, log_callback, chrome_path, thread):
    if not should_continue(thread):
        log_callback("处理已被用户停止。")
        return

    # 从配置中获取参数
    YES_API_KEY = config.get('yes_api_key')
    email_type = config.get('email_type', '')
    TARGET_SENDER = config.get('target_sender', 'info@x.com')
    SIGNUP_URL = 'https://x.com/i/flow/signup'

    CAPTCHA_URL_PATTERN = re.compile(r'https://client-api\.arkoselabs\.com/rtig/image\?.*')

    email_pop_host = ""
    email_pop_prot = ""

    # 新增配置参数
    quick_registration = config.get('quick_registration', False)
    send_messages = config.get('send_messages', False)
    num_messages = config.get('num_messages', 0)

    save_location = config.get('save_location', os.getcwd())
    use_bit_browser = config.get('use_bit_browser', False)
    bit_port = config.get('bit_port', 54345)

    # 日期字符串
    date_str = datetime.now().strftime('%Y%m%d')

    # 设置文件路径
    SUCCESS_FILE = os.path.join(save_location, f'success_{date_str}.txt')
    FAILURE_FILE = os.path.join(save_location, f'failures_{date_str}.txt')
    ALREADY_FILE = os.path.join(save_location, f'already_{date_str}.txt')

    # 用户名随机后缀
    user_name_list = config.get('user_name_list', [])
    name_suffix_enabled = config['name_suffix']['enabled']
    name_suffix_content = config['name_suffix']['content']
    name_suffix_length = config['name_suffix']['length']

    # 发文配置
    activity_enabled = config['activity_enabled']
    activity_img_enabled = config['activity_img_enabled']

    # 上传头像
    upload_avatar_enabled = config['upload_avatar_enabled']
    upload_background_enabled = config['upload_background_enabled']
    avatar_images = config['avatar_images']
    background_images = config['background_images']

    # 启用用户搜索信息
    search_user_enabled = config['search_user_enabled']

    # 打码
    use_api_captcha = config["use_api_captcha"]

    # 上传背景图
    user_profile_list = config.get('user_profile_list', [])
    user_activity_list = config.get('user_activity_list', [])
    user_activity_img_list = config.get('user_activity_img_list', [])
    user_address_list = config.get('user_address_list', [])

    try:
        if email_type == '自建邮箱':
            email_host = config['custom_email_config']['email_host']
            email_pop_host = config['custom_email_config']['email_pop_host']
            email_pop_prot = config['custom_email_config']['email_pop_prot']

            email, email_password, client_id = line_str.split('----')
            t1 = '自建邮箱'
            # 生成用户信息
            password = email_password
            email_api = EmailAPI(email_host, client_id)
            result = await email_api.create_email_account(email, email_password)

            if result['success']:
                log_callback(f"账户创建成功 {email}")
                print(f"账户创建成功: {result['data']}")
            else:
                log_callback(f"创建失败邮件错误：{result['error']}")
                return
        elif email_type == 'Firstmail':
            email, email_password = line_str.split('----')
            t1 = 'Firstmail'
            password = email_password
            client_id = ''

        else:
            email, email_password, client_id, t1 = line_str.split('----')
            # 生成用户信息
            password = generate_password()
    except ValueError:
        log_callback(f"邮箱格式错误：{line_str}")
        return

    if user_name_list:
        user_name = random.choices(user_name_list)[0]
        full_name = user_name.split("----")
        firstname = full_name[0]
        lastname = full_name[1]
    else:
        firstname, lastname = generate_random_full_name()

    # 获取是否添加姓名后缀，为空则根据数量生成
    if name_suffix_enabled:
        if len(name_suffix_content) > 0:
            lastname += name_suffix_content
        else:
            lastname += generate_password(name_suffix_length)

    birth_year, month, day = calculate_date_of_birth(age=22)

    try:

        # 设置插件
        yes_extension = get_extension_path("google_pro_1.1.64") if not use_api_captcha else None
        aiikkebak_extension = get_extension_path("extension_aiikkebakcmeanoofijmcaficpneegpd")
        aknmkinid_extension = get_extension_path("extension_aknmkinilmekpcfajlaehpmappkdlabj")
        cnglcfnjh_extension = get_extension_path("extension_cnglcfnjhnmlhfbcfoniihllidmaincf")

        # 创建插件列表，只包含存在的插件
        extensions = [ext for ext in [yes_extension, aiikkebak_extension, aknmkinid_extension, cnglcfnjh_extension] if
                      ext]

        async with async_playwright() as p:
            if use_bit_browser:
                bit_api = BitAPI(host='127.0.0.1', port=bit_port)
                bro_id = await bit_api.createBrowser()
                res = await bit_api.openBrowser(bro_id)
                if res['success']:
                    ws = res['data']['ws']
                    logger.info("成功连接到 Bit 浏览器")
                    log_callback(f"Bit 浏览器连接成功，处理账户 {email}")
                else:
                    logger.error("Bit 浏览器连接失败")
                    log_callback(f"Bit 浏览器连接失败，无法处理账户 {email}")
                    return
                browser = await p.chromium.connect_over_cdp(endpoint_url=ws)
                default_context = browser.contexts[0]
                page = await default_context.new_page()
            else:

                args = [
                    "--disable-blink-features=AutomationControlled"
                ]
                if extensions:
                    args.extend([
                        f"--disable-extensions-except={','.join(extensions)}",
                        f"--load-extension={','.join(extensions)}"
                    ])
                else:
                    print("警告: 没有找到任何有效的插件")


                browser = await p.chromium.launch_persistent_context(
                    headless=False,
                    args=args,
                    executable_path=chrome_path,
                    user_data_dir="",
                    viewport={"width": 800, "height": 500},
                    locale="en-US",
                )
                # 创建新页面
                page = browser.pages[0]

            # 注册账户
            signup_success = await handle_signup(
                page, email, t1, client_id, email_pop_host, email_pop_prot, password, firstname, lastname,
                birth_year, month, day, SIGNUP_URL, YES_API_KEY, use_api_captcha, TARGET_SENDER, CAPTCHA_URL_PATTERN, log_callback
            )

            if signup_success:
                try:
                    if hasattr(thread, 'parent') and hasattr(thread.parent, 'line_strs'):
                        if line_str in thread.parent.line_strs:
                            thread.parent.line_strs.remove(line_str)
                            thread.signals.update_gui.emit(thread.parent.line_strs)
                            log_callback("GUI更新信号已发送")
                        else:
                            log_callback("line_str不在列表中")
                    else:
                        log_callback("缺少必要的属性")
                except Exception as e:
                    log_callback(f"更新GUI时出错: {e}")
                # 记录成功
                await call_to_action(page)
                if upload_avatar_enabled and avatar_images:
                    log_callback("上传头像")
                    await update_images(page, avatar_images)
                else:
                    await click_button(page, 'text=Skip for now')
                user_name = await select_username(page)
                cookies = await page.context.cookies()
                twitter_sess = await extract_token(cookies, "_twitter_sess")
                auth_token = await extract_token(cookies, "auth_token")
                logger.success(f"注册成功: Email: {email}, Password: {password}, UserName: {user_name}")
                log_callback(f"注册成功: Email: {email}, Password: {password}, UserName: {user_name}")
                if email_type == 'Outlook':
                    async with file_lock:
                        async with aiofiles.open(SUCCESS_FILE, 'a', encoding='utf-8') as success_file:
                            await success_file.write(
                                f"{user_name}----{password}----{email}----{email_password}----{auth_token}----{client_id}----{t1}\n")
                else:
                    async with file_lock:
                        async with aiofiles.open(SUCCESS_FILE, 'a', encoding='utf-8') as success_file:
                            await success_file.write(
                                f"{user_name}----{password}----{email}----{email_password}----{auth_token}\n")

                if not quick_registration:
                    # 完善信息
                    log_callback("完善信息中")
                    await choose_language(page)
                    await click_random_follow_buttons(page, max_clicks=4)
                    await follow_random_topics(page)
                    await follow_accounts(page)

                    if send_messages and num_messages > 0:
                        log_callback("发布推文中")

                        if len(user_activity_list):
                            tweets = user_activity_list
                        await post_tweet(page, num_messages, tweets, activity_enabled, activity_img_enabled,
                                         user_activity_img_list, log_callback)
                    await click_button(page, 'a[aria-label="Profile"]')

                    await set_profile(page, upload_background_enabled, user_profile_list, user_address_list,
                                      background_images)
                    logger.success(f"Email: {email}, 信息完善成功")
                    log_callback(f"Email: {email}, 信息完善成功")

                    if search_user_enabled:
                        await click_button(page, 'a[aria-label="Search and explore"]')
                        log_callback(f"Email: {email}, 开始浏览用户")
                        await search_and_browse_users(page, config)
                        log_callback(f"Email: {email}, 浏览用户完成")

            else:
                # 检查是否已注册
                already_message = page.locator('span:has-text("Email has already been taken.")')
                if await already_message.is_visible():
                    logger.warning(f"已经注册过: Email: {email}, Password: {password}")
                    log_callback(f"已经注册过: Email: {email}, Password: {password}")
                    async with file_lock:
                        async with aiofiles.open(ALREADY_FILE, 'a', encoding='utf-8') as already_file:
                            await already_file.write(f"{email}----{password}\n")
                else:
                    logger.warning(f"注册失败: Email: {email}, Password: {password}")
                    log_callback(f"注册失败: Email: {email}, Password: {password}")
                    async with file_lock:
                        async with aiofiles.open(FAILURE_FILE, 'a', encoding='utf-8') as failure_file:
                            if email_type == '自建邮箱':
                                await failure_file.write(f"{email}----{email_password}\n")
                            elif email_type == 'Firstmail':
                                await failure_file.write(f"{email}----{email_password}\n")
                            else:
                                await failure_file.write(f"{email}----{email_password}----{client_id}----{t1}\n")

            await page.wait_for_timeout(1000)
            await page.close()
            await browser.close()
            if use_bit_browser:
                await bit_api.deleteBrowser(bro_id)

    except Exception as e:
        logger.error(f"处理账户 {email} 时发生错误: {e}")
        log_callback(f"处理账户 {email} 时发生错误: {e}")
        # 记录失败
        async with file_lock:
            async with aiofiles.open(FAILURE_FILE, 'a', encoding='utf-8') as failure_file:
                if email_type == '自建邮箱':
                    await failure_file.write(f"{email}----{email_password}\n")
                elif email_type == 'Firstmail':
                    await failure_file.write(f"{email}----{email_password}\n")
                else:
                    await failure_file.write(f"{email}----{email_password}----{client_id}----{t1}\n")
    finally:
        if use_bit_browser and bro_id:
            await bit_api.deleteBrowser(bro_id)

    logger.info(f"处理完成：{email}")
    log_callback(f"处理完成：{email}")


async def run_automation(config, line_str, log_callback, chrome_path, thread):
    # 将处理过程放在异步函数中
    await process_account(line_str, config, log_callback, chrome_path, thread)


def should_continue(thread):
    return thread._is_running
